import { ProgrammeView } from '../view/programme2019';

import { Programme } from '../compute/programme2019';

/**
 * 节目单画面
 * 该场景非固定长宽: 1920 x 1080
 * 
 * HTML 设置方案
 * #main
 *   #zrender (zrender)
 */

function createScene(context) {
  let t = new App(context);
  global.t = t;
  let scene = new context.Scene({
    require : ['zrender'],
    init : (libs) => t.init(libs),
    destroy : () => t.destroy(),
    collectInfo : () => t.collectInfo(),
    onMessage : (key, data) => t.onMessage(key, data),
  });
  t.sendStatus = scene.sendStatus;
  return scene;
};

const MAX_PROGRAMMES_COUNT = 9;

class App {
  constructor(context) {
    this.context = context;
  }

  // wait for overwrite
  sendStatus() {}

  init(libs) {
    initDom();
    
    this.view = new ProgrammeView({
      context : this.context,
      zrender : libs.zrender,
      dom : elZRender,
    });
    this.view.startTick();

    /** @type {Programme[]} */
    this.programmes = [
      ['19:00', '外星战将', 'Any%', 'NES', '小男孩', 'Dream of sha', '猥琐的阎魔'],
      ['19:40', '赤影战士', 'Any%', 'NES', '毛哥'],
      ['20:00', '冒险岛3', 'Any%', 'NES', '毛哥'],
      ['20:30', '超级马里奥', 'Any%', 'NES', '千千晚星'],
      ['21:00', '超惑星战记', 'Any%', 'NES', '天天老虾', '战神意志'],
      ['21:55', '洛克人X', '100%', 'SNES', '魅友黑帮'],
      ['22:45', '信使', 'Any%-8Bit', 'PC', '沉默的诸葛'],
      ['23:30', '三目童子', 'Any%', 'NES', '忆曲殇璃', '菟斯基', '潇洒の疯子'],
    ].map(strs => {
      const p = new Programme();
      p.prefix = strs[0];
      p.title = strs[1];
      p.subtitles.push(strs[2], strs[3]);
      p.suffix.push(...strs.slice(4));
      p.suffixType = (p.suffix.length > 1) ? 'combat' : 'normal';
      return p;
    });
    this.order = this.programmes.map(p => p.id);
    this.currentIndex = 0; // 是 this.order 的 index
    this.show();
  }

  destroy() {}

  collectInfo() {
    return {
      programmes : this.programmes,
      order : this.order,
      currentIndex : this.currentIndex,
    };
  }

  show() {
    let ps = [];
    const len = Math.min(MAX_PROGRAMMES_COUNT, this.order.length - this.currentIndex);
    for (let i = this.currentIndex; i < len; i++) {
      ps.push(this.programmes.find(p => p.id == this.order[i]));
    }
    this.view.setProgrammes(ps);
  }

  onMessage(key, value) {
    switch (key) {
      // 创建一个新的节目, 放在最后. 但界面上最多只显示 MAX_PROGRAMMES_COUNT 个.
      // value: {prefix:string, title:string, subtitles:string[], suffixType:string, suffix:string[]}
      case 'create': {
        this.handleCreate(value);
        this.sendStatus();
      } return;
      // 创建一个新的节目, 放在最后. 但界面上最多只显示 MAX_PROGRAMMES_COUNT 个.
      // value: {prefix:string, title:string, subtitles:string[], suffixType:string, suffix:string[], id:number}
      case 'update': {
        this.handleUpdate(value.id, value);
        this.sendStatus();
      } return;
      // 重新排序节目表. 也用于删除原有节目
      // value: {order:number[], currentIndex:number?}
      // currentIndex 如果不设置, 那就是 0
      case 'sort': {
        this.handleSort(value.order, value.currentIndex);
        this.sendStatus();
      } return;
    }
    console.log('board_2018/programme2019 收到无法处理的消息', key, value);
  }

  /**
   * @param {{prefix:string, title:string, subtitles:string[], suffixType:string, suffix:string[]}} args 
   */
  handleCreate(args) {
    if (typeof(args.prefix) != 'string') throw {msg: '无法创建: prefix 数据错误'};
    if (typeof(args.title) != 'string') throw {msg: '无法创建: title 数据错误'};
    if (args.suffixType != 'normal' && args.suffixType != 'combat') throw {msg: '无法创建: suffixType 数据错误'};
    if (!(args.subtitles instanceof Array)) throw {msg: '无法创建: subtitles 数据错误'};
    if (args.subtitles.some(s => typeof(s) != 'string')) throw {msg: '无法创建: subtitles 数据错误'};
    if (!(args.suffix instanceof Array)) throw {msg: '无法创建: suffix 数据错误'};
    if (args.suffix.some(s => typeof(s) != 'string')) throw {msg: '无法创建: subtitles 数据错误'};

    let p = new Programme();
    p.prefix = args.prefix;
    p.title = args.title;
    p.suffixType = args.suffixType;
    p.subtitles.push(...args.subtitles);
    p.suffix.push(...args.suffix);

    this.programmes.push(p);
    this.order.push(p.id);
    this.show();
  }

  /**
   * @param {number} id
   * @param {{prefix?:string, title?:string, subtitles?:string[], suffixType?:string, suffix?:string[]}} args 
   */
  handleUpdate(id, args) {
    if (typeof(id) != 'number') throw {msg: '无法更新: id 数据错误'};

    let p = this.programmes.find(p => p.id == id);

    if (args.prefix && typeof(args.prefix) == 'string') {
      p.prefix = args.prefix;
    }
    if (args.title && typeof(args.title) == 'string') {
      p.title = args.title;
    }
    if (args.suffixType == 'normal' || args.suffixType == 'combat') {
      p.suffixType = args.suffixType;
    }
    if (args.subtitles && args.subtitles instanceof Array && args.subtitles.every(s => typeof(s) == 'string')) {
      p.subtitles = args.subtitles;
    }
    if (args.suffix && args.suffix instanceof Array && args.suffix.every(s => typeof(s) == 'string')) {
      p.suffix = args.suffix;
    }
    this.show();
  }

  /**
   * @param {number[]} ids 
   * @param {number} currentIndex 
   */
  handleSort(ids, currentIndex = 0) {
    if (!(ids instanceof Array)) throw {msg: '无法重排序: order 数据错误'};
    if (ids.some(s => typeof(s) != 'number')) throw {msg: '无法重排序: order 数据错误'};
    if (typeof(currentIndex) != 'number') throw {msg: '无法重排序: currentIndex 数据错误'};

    for (let i = ids.length - 1; i >= 0; i--) {
      let exists = this.programmes.some(p => p.id == ids[i]);
      if (!exists) {
        ids.splice(i, 1);
      }
      if (currentIndex > i) {
        --currentIndex;
      }
    }

    this.order = ids;
    this.programmes = this.programmes.filter(p => ids.includes(p.id));
    if (currentIndex >= ids.length && ids.length != 0) {
      currentIndex = ids.length - 1;
    }
    this.currentIndex = currentIndex;
    this.show();
  }
}

/** @type {HTMLElement} */ let elMain;
/** @type {HTMLElement} */ let elZRender;

function initDom(width = 1920, height = 1080) {
  elMain = document.getElementById('main');

  elZRender = document.createElement('div');
  elZRender.id = 'zrender';
  elZRender.style.position = 'absolute';
  elZRender.style.overflow = 'hidden';
  elZRender.style.left = '0px';
  elZRender.style.top = '0px';
  elZRender.style.width = width + 'px';
  elZRender.style.height = height + 'px';
  elZRender.style.zIndex = '0';
  elMain.appendChild(elZRender);

  return [elMain, elZRender];
}

export default createScene;
